﻿// CoinExample.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <Inventor/Win/SoWin.h>
#include <Inventor/win/viewers/SoWinExaminerViewer.h>
#include <Inventor/nodes/SoCube.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoBaseColor.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoDrawStyle.h>
#include <Inventor/SoDB.h>
#include <Inventor/nodes/SoLineSet.h>
#include <Inventor/nodes/SoMaterial.h>
#include <Inventor/nodes/SoCoordinate3.h>
#include <Inventor/nodes/SoFaceSet.h>
#include <Inventor/nodes/SoIndexedFaceSet.h>
#include <vector>
#include <array> 
#include "earcut.hpp" // 需下载 earcut.hpp
using Coord = double;

// The index type. Defaults to uint32_t, but you can also pass uint16_t if you know that your
// data won't have more than 65536 vertices.
using N = uint32_t;

// Create array
using Point = std::array<Coord, 2>;
void draw_line(SoSeparator* root, const std::vector<SbVec3f>& polygon, const std::vector<std::vector<SbVec3f>>& holes);
int main(int argc, char** argv)
{
    // std::cout << "Hello World!\n";
    HWND myWindow = SoWin::init(argv[0]);
    if (myWindow == NULL)
        exit(1);

    SoDB::init();

    // 创建场景根节点
    SoSeparator* root = new SoSeparator;
    root->ref();

    //// 添加光照
    //SoDirectionalLight* light = new SoDirectionalLight;
    //light->direction.setValue(0, 0, -1);
    //root->addChild(light);

    // 创建一个分隔符节点用于填充部分
    SoSeparator* fillSeparator = new SoSeparator;
    root->addChild(fillSeparator);

    // 1. 定义材质（红色填充）
    SoMaterial* mat = new SoMaterial;
    mat->diffuseColor.setValue(1.0f, 0.0f, 0.0f); // 红色
    fillSeparator->addChild(mat);
    
    //SoDrawStyle* drawStyle = new SoDrawStyle;
    //drawStyle->style = SoDrawStyle::LINES;
    //drawStyle->pointSize = 2.0f;
    //drawStyle->lineWidth = 2.0f;
    //fillSeparator->addChild(drawStyle);
    // 定义L形多边形顶点
/*    std::vector<SbVec3f> polygon = {
        SbVec3f(-50, -100, 0),
        SbVec3f(50, -100, 0),
        SbVec3f(50, 100, 0),
        SbVec3f(40, 100, 0),
        SbVec3f(40, -90, 0),
        SbVec3f(-50, -90, 0)
    };
    std::vector<std::vector<SbVec3f>> holes = {};
    */
    // 定义回字形的多边形
   
    std::vector<SbVec3f> polygon =
    {
        SbVec3f(-50, -50, 0),
        SbVec3f(50, -50, 0),
        SbVec3f(50, 50, 0),
        SbVec3f(-50, 50, 0),
    };

    std::vector<std::vector<SbVec3f>> holes = {
      {
       SbVec3f(-40, -40, 0),  // 内环：左下→左上→右上→右下
    SbVec3f(-40, 40, 0),
    SbVec3f(40, 40, 0),
    SbVec3f(40, -40, 0)
      }
    };
   
    // earcut 需要二维数组，转换为 std::vector<std::vector<std::array<double, 2>>>
    std::vector<std::vector<Point>> earcutPolygon;
    std::vector<Point> earcutPoints;
    for (const auto& pt : polygon) {
        earcutPoints.push_back({ pt[0], pt[1] });
    }
    earcutPolygon.push_back(earcutPoints);
    for (const auto& hole : holes) {
        std::vector<Point> earcutHolePoints;
        for (const auto& pt : hole) {
            earcutHolePoints.push_back({ pt[0], pt[1] });
        }
        earcutPolygon.push_back(earcutHolePoints);
    }

    // 三角化
    std::vector<uint32_t> indices = mapbox::earcut<uint32_t>(earcutPolygon);

    // 设置顶点
    SoCoordinate3* coords = new SoCoordinate3;
    size_t idx = 0;

    // 添加外环顶点
    for (const auto& pt : polygon) {
        coords->point.set1Value(idx++, pt[0], pt[1], pt[2]);
    }

    // 添加所有内环顶点
    for (const auto& hole : holes) {
        for (const auto& pt : hole) {
            coords->point.set1Value(idx++, pt[0], pt[1], pt[2]);
        }
    }

    fillSeparator->addChild(coords);

    // 打印所有顶点
    std::cout << "所有顶点:" << std::endl;
    for (size_t i = 0; i < idx; ++i) {
        const SbVec3f& v = coords->point[i];
        std::cout << "Vertex " << i << ": " << v[0] << ", " << v[1] << ", " << v[2] << std::endl;
    }

    // 打印所有三角形索引
    std::cout << "所有三角形索引:" << std::endl;
    for (size_t i = 0; i < indices.size(); i += 3) {
        std::cout << "Triangle: " << indices[i] << ", " << indices[i + 1] << ", " << indices[i + 2] << std::endl;
    }

    // 用 SoIndexedFaceSet 渲染三角形
    SoIndexedFaceSet* indexedFaceSet = new SoIndexedFaceSet;
    size_t idXx = 0;
    for (size_t i = 0; i < indices.size(); i += 3) {
        indexedFaceSet->coordIndex.set1Value(idXx++, indices[i]);
        indexedFaceSet->coordIndex.set1Value(idXx++, indices[i + 1]);
        indexedFaceSet->coordIndex.set1Value(idXx++, indices[i + 2]);
        indexedFaceSet->coordIndex.set1Value(idXx++, -1); // 分隔三角面
    }
    fillSeparator->addChild(indexedFaceSet);
    //draw_line(root,polygon,holes);
   
    SoWinExaminerViewer* myViewer = new SoWinExaminerViewer(myWindow);
    myViewer->setSceneGraph(root);
    myViewer->setTitle("带孔洞的多边形示例");
    // myViewer->setBackgroundColor(SbColor(1, 1, 1)); // 白色背景
    myViewer->show();

    SoWin::show(myWindow);
    SoWin::mainLoop();

    return 0;
}

void draw_line(SoSeparator* root, const std::vector<SbVec3f>& polygon, const std::vector<std::vector<SbVec3f>>& holes) {
    // 创建一个分隔符节点用于边框线
    SoSeparator* lineSeparator = new SoSeparator;
    root->addChild(lineSeparator);
    SoCoordinate3* coords_line = new SoCoordinate3;
    size_t idx_line = 0;
    for (const auto& pt : polygon) {
        coords_line->point.set1Value(idx_line++, pt);
    }
    coords_line->point.set1Value(idx_line++, polygon[0]); // 闭合
    lineSeparator->addChild(coords_line);
    // 定义边框线材质（黑色）
    SoMaterial* lineMat = new SoMaterial;
    lineMat->diffuseColor.setValue(0.0f, 1.0f, 1.0f); // 黑色
    lineSeparator->addChild(lineMat);

    // 设置线宽和线型
    SoDrawStyle* drawStyle = new SoDrawStyle;
    drawStyle->style = SoDrawStyle::LINES;
    drawStyle->lineWidth = 2.0f; // 线宽
    drawStyle->linePattern = 0xF0F0; // 虚线模式
    lineSeparator->addChild(drawStyle);
    // 外环边框线
    SoLineSet* outerLineSet = new SoLineSet;
    outerLineSet->numVertices.setValue(polygon.size() + 1); // 闭合线，需要回到起点
    lineSeparator->addChild(outerLineSet);

    // 内环边框线
    //for (const auto& hole : holes) {
    //    for (const auto& pt : hole) {
    //        coords_line->point.set1Value(idx_line++, pt);
    //    }
    //    coords_line->point.set1Value(idx_line++, hole[0]); // 闭合
    //    SoLineSet* holeLineSet = new SoLineSet;
    //    holeLineSet->numVertices.setValue(hole.size() + 1);
    //    lineSeparator->addChild(holeLineSet);
    //}
}
